//
//  UIView_snapshot.swift
//  MyLibrary
//
//  Created by 周博 on 2020/6/22.
//  Copyright © 2020 ncit. All rights reserved.
//

import UIKit
import AVKit


// MARK: 截屏
public extension UIView {

    var fastSnapshot_imageView: UIImageView? {

        get {
            UIGraphicsBeginImageContextWithOptions(self.bounds.size, false, UIScreen.main.scale)
            self.drawHierarchy(in: self.bounds, afterScreenUpdates: false)
            let image = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
            return UIImageView(image: image)
        }
    }
    
    var fastSnapshot: UIImage? {

        get {
            UIGraphicsBeginImageContextWithOptions(self.bounds.size, false, UIScreen.main.scale)
            self.drawHierarchy(in: self.bounds, afterScreenUpdates: false)
            let image = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
            return image
        }
    }

    var snapShot_imageView: UIImageView? {

        get {
            UIGraphicsBeginImageContextWithOptions(self.bounds.size, false, UIScreen.main.scale)
            guard let context = UIGraphicsGetCurrentContext() else { return nil }
            self.layer.render(in: context)
            let image = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
            return UIImageView(image: image)
        }
    }
    
    var snapShot: UIImage? {

        get {
            UIGraphicsBeginImageContextWithOptions(self.bounds.size, false, UIScreen.main.scale)
            guard let context = UIGraphicsGetCurrentContext() else { return nil }
            self.layer.render(in: context)
            let image = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
            return image
        }
    }
}


public extension AVPlayer {
    
    // 运行时添加属性的key
    private struct AssociateKeys {
        static var videoOutput_key = "videoOutput_key"
        static var CVPixelBuffer_Key = "CVPixelBuffer_Key"
        static var displayLink_key = "displayLink_key"
        static var applyForScreenShopBlock_key = "applyForScreenShopBlock_key"
    }
    
    /**
     * 申请获取视频截图, 异步
     */
    func applyForScreenShot(successCallBack: @escaping (UIImage)->Void) {
        
        
        applyForScreenShopBlock = successCallBack
        guard let playerItem = self.currentItem else {
            return
        }
        
        if self.videoOutput == nil {
            self.videoOutput = AVPlayerItemVideoOutput(pixelBufferAttributes: nil)
            playerItem.remove(self.videoOutput!)
            playerItem.add(self.videoOutput!)
        }
        
        guard let _ = self.videoOutput else {
            return
        }
        
        if displayLink == nil {
            displayLink = CADisplayLink(target: self, selector: #selector(displayLinkDo))
            displayLink.add(to: RunLoop.main, forMode: .common)
        }
        displayLink.isPaused = false
    }
    
    
    @objc private func displayLinkDo() {
        
        DispatchQueue.global().async {
            
            self.asynSnapTask()

        }
    }
    
    private func asynSnapTask() {
        guard let time = videoOutput?.itemTime(forHostTime: CACurrentMediaTime()) else {return}
        
        if self.videoOutput!.hasNewPixelBuffer(forItemTime: time) {
            lastSnapshotPixelBuffer = videoOutput!.copyPixelBuffer(forItemTime: time, itemTimeForDisplay: nil)
            
            if lastSnapshotPixelBuffer != nil {
                let ciImage = CIImage(cvPixelBuffer: lastSnapshotPixelBuffer!)
                let context = CIContext(options: nil)
                let rect = CGRect(x: CGFloat(0), y: CGFloat(0), width: CGFloat(CVPixelBufferGetWidth(lastSnapshotPixelBuffer!)), height: CGFloat(CVPixelBufferGetHeight(lastSnapshotPixelBuffer!)))
                let cgImage = context.createCGImage(ciImage, from: rect)
                if cgImage != nil {
                    let image = UIImage(cgImage: cgImage!)
                    
                    displayLink.isPaused = true
                    
                    DispatchQueue.main.async {
                        self.applyForScreenShopBlock?(image)
                    }
                }
            }
        }
    }
    
    
    // MARK: 私有属性
    
    /** 视频截图所需要的output */
    private var videoOutput: AVPlayerItemVideoOutput? {
        get {
            if let a = objc_getAssociatedObject(self, &AssociateKeys.videoOutput_key) as? AVPlayerItemVideoOutput {
                return a
            }
            return nil
        }
        set {
            
            // zwarning: OBJC_ASSOCIATION_ASSIGN 使用这个坑逼, 不能正确存储
            objc_setAssociatedObject(self, &AssociateKeys.videoOutput_key, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    
    
    private var lastSnapshotPixelBuffer: CVPixelBuffer? {
        get {
            if let a = objc_getAssociatedObject(self, &AssociateKeys.CVPixelBuffer_Key) {
                return a as! CVPixelBuffer
            }
            return nil
        }
        set {
            
            // zwarning: OBJC_ASSOCIATION_ASSIGN 使用这个坑逼, 不能正确存储
            objc_setAssociatedObject(self, &AssociateKeys.CVPixelBuffer_Key, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }


    
    /** 定时器 */
    private var displayLink: CADisplayLink! {
        get {
            if let a = objc_getAssociatedObject(self, &AssociateKeys.displayLink_key) as? CADisplayLink {
                return a
            }
            return nil
        }
        set {
            
            // zwarning: OBJC_ASSOCIATION_ASSIGN 使用这个坑逼, 不能正确存储
            objc_setAssociatedObject(self, &AssociateKeys.displayLink_key, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    
    private var applyForScreenShopBlock: ((UIImage)->Void)? {
        get {
            if let a = objc_getAssociatedObject(self, &AssociateKeys.applyForScreenShopBlock_key) as? ((UIImage)->Void) {
                return a
            }
            return nil
        }
        set {
            
            // zwarning: OBJC_ASSOCIATION_ASSIGN 使用这个坑逼, 不能正确存储
            objc_setAssociatedObject(self, &AssociateKeys.applyForScreenShopBlock_key, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
}


// MARK: 手势封装
public extension UIView {
    
    // 运行时添加属性的key
    private struct AssociateKeys {
        static var tap_gestureBlock_key = "tap_gestureBlock_key"
        static var double_tap_gestureBlock_key = "double_tap_gestureBlock_key"
        static var pan_gestureBlock_key = "pan_gestureBlock_key"
        static var longPress_gestureBlock_key = "longPress_gestureBlock_key"
    }
    
    typealias TapGestureBlock = (UITapGestureRecognizer) -> Void
    typealias PanGestureBlock = (UIPanGestureRecognizer) -> Void
    typealias LongPressGestureBlock = (UILongPressGestureRecognizer) -> Void

    // 单击tap手势处理回调属性
    private var tapGestureBlock: TapGestureBlock? {
        get {
            return objc_getAssociatedObject(self, &AssociateKeys.tap_gestureBlock_key) as? TapGestureBlock
        }
        set {
            objc_setAssociatedObject(self, &AssociateKeys.tap_gestureBlock_key, newValue, .OBJC_ASSOCIATION_COPY)
        }
    }
    
    // 双击tap手势处理回调属性
    private var doubleTapGestureBlock: TapGestureBlock? {
        get {
            return objc_getAssociatedObject(self, &AssociateKeys.double_tap_gestureBlock_key) as? TapGestureBlock
        }
        set {
            objc_setAssociatedObject(self, &AssociateKeys.double_tap_gestureBlock_key, newValue, .OBJC_ASSOCIATION_COPY)
        }
    }
    
    // pan手势处理回调属性
    private var panGestureBlock: PanGestureBlock? {
        get {
            return objc_getAssociatedObject(self, &AssociateKeys.pan_gestureBlock_key) as? PanGestureBlock
        }
        set {
            objc_setAssociatedObject(self, &AssociateKeys.pan_gestureBlock_key, newValue, .OBJC_ASSOCIATION_COPY)
        }
    }
    
    // 长按手势处理回调属性
    private var longPressGestureBlock: LongPressGestureBlock? {
        get {
            return objc_getAssociatedObject(self, &AssociateKeys.longPress_gestureBlock_key) as? LongPressGestureBlock
        }
        set {
            objc_setAssociatedObject(self, &AssociateKeys.longPress_gestureBlock_key, newValue, .OBJC_ASSOCIATION_COPY)
        }
    }
    
    // 手势处理
    @objc private func tapGestureSelector(gesture: UITapGestureRecognizer) {
        tapGestureBlock?(gesture)
    }
    
    // 手势处理
    @objc private func doubleTapGestureSelector(gesture: UITapGestureRecognizer) {
        doubleTapGestureBlock?(gesture)
    }
    
    // 手势处理
    @objc private func panGestureSelector(gesture: UIPanGestureRecognizer) {
        panGestureBlock?(gesture)
    }
    
    // 手势处理
    @objc private func longPressGestureSelector(gesture: UILongPressGestureRecognizer) {
        
        if gesture.state == .began {
            longPressGestureBlock?(gesture)
        }
    }
    
    /**
     * 添加单击tap手势
     */
    func addTapGesture(gestureBlock: @escaping TapGestureBlock) -> UITapGestureRecognizer {
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(tapGestureSelector(gesture:)))
        tapGesture.numberOfTapsRequired = 1
        addGestureRecognizer(tapGesture)
        
        tapGestureBlock = gestureBlock
        return tapGesture
    }
    
    /**
     * 添加双击tap手势
     */
    func addDoubleTapGesture(gestureBlock: @escaping TapGestureBlock) -> UITapGestureRecognizer {
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(doubleTapGestureSelector(gesture:)))
        tapGesture.numberOfTapsRequired = 2
        addGestureRecognizer(tapGesture)
        
        doubleTapGestureBlock = gestureBlock
        return tapGesture
    }
        
    /**
     * 添加滑动手势
     */
    func addPanGesture(gestureBlock: @escaping PanGestureBlock) -> UIPanGestureRecognizer {
        let panGesture = UIPanGestureRecognizer(target: self, action: #selector(panGestureSelector(gesture:)))
        addGestureRecognizer(panGesture)
        
        panGestureBlock = gestureBlock
        return panGesture
    }
    
//    /**
//     * 添加双击手势
//     */
//    func addDoubleTapGesture(gestureAction: @escaping PanGestureAction) -> UITapGestureRecognizer {
//        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(panGestureSelector(gesture:)))
//        tapGesture.numberOfTouchesRequired = 1
//        tapGesture.numberOfTapsRequired = 1
//        addGestureRecognizer(tapGesture)
//        return tapGesture
//    }
//
    /**
     * 添加长按手势
     */
    func addLongPressGesture(gestureBlock: @escaping LongPressGestureBlock) -> UILongPressGestureRecognizer {
        let longGesture = UILongPressGestureRecognizer(target: self, action: #selector(longPressGestureSelector(gesture:)))
        self.addGestureRecognizer(longGesture)
        
        longPressGestureBlock = gestureBlock
        return longGesture
    }
    
}
